package org.zjx.window.window;

import lombok.Getter;
import org.zjx.window.operation.WindowOperation;

import java.awt.*;
import java.util.Objects;

/**
 * 操作序列构建器
 * 提供流畅的API用于构建和执行窗口操作序列
 *
 * @author zjx
 * @since 1.0
 */
@Getter
public class ActionBuilder {

    /**
     * 目标窗口
     * -- GETTER --
     *  获取目标窗口
     */
    private final IWindow window;

    /**
     * 私有构造方法
     *
     * @param window 目标窗口
     */
    private ActionBuilder(IWindow window) {
        this.window = Objects.requireNonNull(window, "目标窗口不能为null");
    }

    /**
     * 创建针对指定窗口的操作构建器
     *
     * @param window 目标窗口，不能为null
     * @return 操作构建器实例
     * @throws IllegalArgumentException 如果window为null
     */
    public static ActionBuilder on(IWindow window) {
        return new ActionBuilder(window);
    }

    // ========== 屏幕绝对坐标移动操作 ==========

    /**
     * 移动鼠标到屏幕绝对坐标
     *
     * @param x 屏幕绝对X坐标
     * @param y 屏幕绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder moveTo(int x, int y) {
        window.execute(WindowOperation.move(x, y));
        return this;
    }

    /**
     * 移动鼠标到屏幕绝对坐标（双精度版本）
     *
     * @param x 屏幕绝对X坐标
     * @param y 屏幕绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder moveTo(double x, double y) {
        return moveTo((int) x, (int) y);
    }

    /**
     * 移动鼠标到屏幕绝对坐标点
     *
     * @param point 屏幕绝对坐标点，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果point为null
     */
    public ActionBuilder moveTo(Point point) {
        Objects.requireNonNull(point, "目标点不能为null");
        return moveTo(point.x, point.y);
    }

    /**
     * 移动鼠标到屏幕区域内随机位置
     *
     * @param area 屏幕区域，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果area 为null
     */
    public ActionBuilder moveTo(Rectangle area) {
        Objects.requireNonNull(area, "移动区域不能为 null");
        return moveTo(area.getCenterX(), area.getCenterY());
    }

    // ========== 游戏窗口相对坐标移动操作 ==========

    /**
     * 移动鼠标到游戏窗口内相对坐标
     *
     * @param x 窗口内相对X坐标
     * @param y 窗口内相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder gameMoveTo(int x, int y) {
        window.execute(WindowOperation.gameMove(x, y));
        return this;
    }

    /**
     * 移动鼠标到游戏窗口内相对坐标（双精度版本）
     *
     * @param x 窗口内相对X坐标
     * @param y 窗口内相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder gameMoveTo(double x, double y) {
        return gameMoveTo((int) x, (int) y);
    }

    /**
     * 移动鼠标到游戏窗口内相对坐标点
     *
     * @param point 窗口内相对坐标点，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果point为null
     */
    public ActionBuilder gameMoveTo(Point point) {
        Objects.requireNonNull(point, "目标点不能为null");
        return gameMoveTo(point.x, point.y);
    }

    /**
     * 移动鼠标到游戏窗口内区域内的随机位置
     *
     * @param area 窗口内相对区域，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果area为null
     */
    public ActionBuilder gameMoveTo(Rectangle area) {
        Objects.requireNonNull(area, "移动区域不能为null");
        window.execute(WindowOperation.gameMove(area));
        return this;
    }

    // ========== 点击操作（默认使用游戏窗口相对坐标） ==========

    /**
     * 在当前鼠标位置点击（左键）
     *
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder click() {
        window.execute(WindowOperation.click(1));
        return this;
    }

    /**
     * 在当前鼠标位置点击指定按钮
     *
     * @param button 鼠标按钮：1-左键, 2-中键, 3-右键
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果button不是1,2,3
     */
    public ActionBuilder click(int button) {
        if (button < 1 || button > 3) {
            throw new IllegalArgumentException("无效的鼠标按钮: " + button);
        }
        window.execute(WindowOperation.click(button));
        return this;
    }

    /**
     * 在游戏窗口内指定相对坐标点击（左键）
     *
     * @param x 窗口内相对X坐标
     * @param y 窗口内相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder clickAt(int x, int y) {
        return gameMoveTo(x, y).delay(30).click();
    }

    /**
     * 在游戏窗口内指定相对坐标点击（左键，双精度版本）
     *
     * @param x 窗口内相对X坐标
     * @param y 窗口内相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder clickAt(double x, double y) {
        return clickAt((int) x, (int) y);
    }

    /**
     * 在游戏窗口内指定区域内随机点击
     *
     * @param area 窗口内相对点击区域，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果area为null
     */
    public ActionBuilder clickIn(Rectangle area) {
        Objects.requireNonNull(area, "点击区域不能为null");
        return gameMoveTo(area).delay(30).click();
    }

    /**
     * 在屏幕绝对坐标点击（左键）
     *
     * @param x 屏幕绝对X坐标
     * @param y 屏幕绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder clickAtScreen(int x, int y) {
        return moveTo(x, y).delay(30).click();
    }

    /**
     * 在屏幕绝对坐标点击（左键，双精度版本）
     *
     * @param x 屏幕绝对X坐标
     * @param y 屏幕绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder clickAtScreen(double x, double y) {
        return clickAtScreen((int) x, (int) y);
    }

    /**
     * 在屏幕区域内随机点击
     *
     * @param area 屏幕绝对区域，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果area为null
     */
    public ActionBuilder clickInScreen(Rectangle area) {
        Objects.requireNonNull(area, "点击区域不能为null");
        return moveTo(area).delay(30).click();
    }

    /**
     * 双击（左键）
     *
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder doubleClick() {
        return click().delay(50).click();
    }

    /**
     * 在游戏窗口内指定相对坐标双击（左键）
     *
     * @param x 窗口内相对X坐标
     * @param y 窗口内相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder doubleClickAt(int x, int y) {
        return clickAt(x, y).delay(50).click();
    }

    // ========== 键盘操作 ==========

    /**
     * 输入文本
     *
     * @param text 要输入的文本，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果text为null
     */
    public ActionBuilder input(String text) {
        Objects.requireNonNull(text, "输入文本不能为null");
        window.execute(WindowOperation.type(text));
        return this;
    }

    /**
     * 按下并释放指定键
     *
     * @param keyCode 键盘键码
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder keyPress(int keyCode) {
        window.execute(WindowOperation.press(keyCode));
        return this;
    }

    /**
     * 执行快捷键组合
     *
     * @param keyCodes 键盘键码序列，不能为空
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果keyCodes为空
     */
    public ActionBuilder hotkey(int... keyCodes) {
        if (keyCodes == null || keyCodes.length == 0) {
            throw new IllegalArgumentException("快捷键键码序列不能为空");
        }
        window.execute(WindowOperation.hotkey(keyCodes));
        return this;
    }

    // ========== 等待操作 ==========

    /**
     * 延迟指定毫秒数
     *
     * @param milliseconds 延迟毫秒数
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果milliseconds为负数
     */
    public ActionBuilder delay(long milliseconds) {
        if (milliseconds < 0) {
            throw new IllegalArgumentException("延迟时间不能为负数: " + milliseconds);
        }
        window.execute(WindowOperation.delay(milliseconds));
        return this;
    }

    /**
     * 延迟指定秒数
     *
     * @param seconds 延迟秒数
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果seconds为负数
     */
    public ActionBuilder delaySeconds(long seconds) {
        if (seconds < 0) {
            throw new IllegalArgumentException("延迟秒数不能为负数: " + seconds);
        }
        return delay(seconds * 1000);
    }

    // ========== 鼠标操作 ==========

    /**
     * 按下鼠标按钮
     *
     * @param button 鼠标按钮：1-左键, 2-中键, 3-右键
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果button不是1,2,3
     */
    public ActionBuilder pressMouse(int button) {
        if (button < 1 || button > 3) {
            throw new IllegalArgumentException("无效的鼠标按钮: " + button);
        }
        window.execute(WindowOperation.pressMouse(button));
        return this;
    }

    /**
     * 释放鼠标按钮
     *
     * @param button 鼠标按钮：1-左键, 2-中键, 3-右键
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果button不是1,2,3
     */
    public ActionBuilder releaseMouse(int button) {
        if (button < 1 || button > 3) {
            throw new IllegalArgumentException("无效的鼠标按钮: " + button);
        }
        window.execute(WindowOperation.releaseMouse(button));
        return this;
    }

    /**
     * 拖拽操作（使用游戏窗口相对坐标）
     *
     * @param fromX 起点相对X坐标
     * @param fromY 起点相对Y坐标
     * @param toX 终点相对X坐标
     * @param toY 终点相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder drag(int fromX, int fromY, int toX, int toY) {
        window.execute(WindowOperation.drag(fromX, fromY, toX, toY));
        return this;
    }

    /**
     * 拖拽操作（使用屏幕绝对坐标）
     *
     * @param fromX 起点绝对X坐标
     * @param fromY 起点绝对Y坐标
     * @param toX 终点绝对X坐标
     * @param toY 终点绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder dragScreen(int fromX, int fromY, int toX, int toY) {
        return moveTo(fromX, fromY).delay(50).pressMouse(1).delay(100)
                .moveTo(toX, toY).delay(50).releaseMouse(1);
    }

    /**
     * 从当前点拖拽到指定点（使用游戏窗口相对坐标）
     *
     * @param toX 终点相对X坐标
     * @param toY 终点相对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder dragTo(int toX, int toY) {
        // 先按下鼠标，然后移动，最后释放
        return pressMouse(1).delay(100).gameMoveTo(toX, toY).delay(50).releaseMouse(1);
    }

    /**
     * 从当前点拖拽到指定点（使用屏幕绝对坐标）
     *
     * @param toX 终点绝对X坐标
     * @param toY 终点绝对Y坐标
     * @return 当前构建器实例（用于链式调用）
     */
    public ActionBuilder dragToScreen(int toX, int toY) {
        // 先按下鼠标，然后移动，最后释放
        return pressMouse(1).delay(100).moveTo(toX, toY).delay(50).releaseMouse(1);
    }

    // ========== 组合操作 ==========

    /**
     * 执行自定义窗口操作
     *
     * @param operation 自定义操作，不能为null
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果operation为null
     */
    public ActionBuilder execute(WindowOperation operation) {
        Objects.requireNonNull(operation, "窗口操作不能为null");
        window.execute(operation);
        return this;
    }

    /**
     * 重复执行当前构建的操作序列
     *
     * @param times 重复次数
     * @return 当前构建器实例（用于链式调用）
     * @throws IllegalArgumentException 如果times小于1
     */
    public ActionBuilder repeat(int times) {
        if (times < 1) {
            throw new IllegalArgumentException("重复次数必须大于0: " + times);
        }

        // 注意：这种方法只能重复后续操作，不能重复之前的操作
        // 更复杂的重复逻辑需要不同的设计
        for (int i = 0; i < times; i++) {
            // 这里无法直接重复之前的操作，需要用户显式调用
        }
        return this;
    }

    /**
     * 完成操作序列执行
     * 此方法主要用于语义完整性，实际操作已经在链式调用中执行
     */
    public void execute() {
        // 所有操作已经在链式调用中执行了
        // 此方法主要用于标记操作序列的结束
    }

    /**
     * 构建操作序列但不立即执行
     * 返回一个WindowOperation，可以在需要时执行
     *
     * @param operations 操作序列
     * @return 组合操作实例
     */
    public static WindowOperation buildSequence(WindowOperation... operations) {
        return WindowOperation.sequence(operations);
    }
}